#pragma once

#include<iostream>
#include<string>
#include<queue>
#include<pthread.h>

const int defaultcap = 5;//阻塞队列的大小

template <typename T>
class BlockQueue
{
private:
    bool IsFull()
    {
        return _q.size() >= _cap;
    }
    bool IsEmpty()
    {
        return _q.empty();
    }
public:
    BlockQueue(int cap = defaultcap)
    :_cap(cap),_csleep_num(0),_psleep_num(0)
    {
        pthread_mutex_init(&_mutex,nullptr);//初始化锁
        pthread_cond_init(&_full_cond,nullptr);//初始化条件变量
        pthread_cond_init(&_empty_cond,nullptr);//初始化条件变量
    }
    void Equeue(const T& in)//生产者
    {
        pthread_mutex_lock(&_mutex);//加锁
        while(IsFull())//判断队列是否为满
        {
            //满了阻塞等待
            _psleep_num++;
            std::cout << "队列满了,停止生产,停止的个数:" << _psleep_num << std::endl;
            pthread_cond_wait(&_full_cond,&_mutex);//进行等待前会释放锁,等待成功后会申请锁
            _psleep_num--;
        }
        //证明一定有空间
        std::cout << "发送一个任务" << std::endl;
        _q.push(in);
        if(_csleep_num > 0)//唤醒消费者
        {
            std::cout << "唤醒一个消费者" << std::endl;
            pthread_cond_signal(&_empty_cond);
        }
        pthread_mutex_unlock(&_mutex);//解锁
    }

    T Pop()
    {
        pthread_mutex_lock(&_mutex);
        while(IsEmpty())
        {
            //队列为空消费者进行阻塞等待
            _csleep_num++;
            std::cout << "队列为空,停止获取资源,停止的个数:" << _csleep_num << std::endl;
            pthread_cond_wait(&_empty_cond,&_mutex);
            _csleep_num--;
        }
        std::cout << "获取一个任务" << std::endl;
        T data = _q.front();
        _q.pop();

        if(_psleep_num > 0)
        {
            std::cout << "唤醒一个生产者" << std::endl;
            pthread_cond_signal(&_full_cond);
        }
        pthread_mutex_unlock(&_mutex);
        return data;
    }
    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);//释放锁
        pthread_cond_destroy(&_full_cond);//释放条件变量
        pthread_cond_destroy(&_empty_cond);//释放条件变量
    }
private:
    std::queue<T> _q;//临界资源
    int _cap;//临街资源的容量

    pthread_mutex_t _mutex;//维护临界变量的锁
    pthread_cond_t _full_cond;//队列满时的条件变量
    pthread_cond_t _empty_cond;//队列为空时的条件变量

    int _csleep_num;//消费者休眠的个数
    int _psleep_num;//生产者休眠的个数
};